#ifndef __MCP23S17_H__
#define __MCP23S17_H__

#include <stdint.h>

#define BANK0_IODIRA 0x00U
#define BANK0_IODIRB 0x01U
#define BANK0_IPOLA 0x02U
#define BANK0_IPOLB 0x03U
#define BANK0_GPINTENA 0x04U
#define BANK0_GPINTENB 0x05U
#define BANK0_DEFVALA 0x06U
#define BANK0_DEFVALB 0x07U
#define BANK0_INTCONA 0x08U
#define BANK0_INTCONB 0x09U
#define BANK0_IOCONA 0x0AU
#define BANK0_IOCONB 0x0BU
#define BANK0_GPPUA 0x0CU
#define BANK0_GPPUB 0x0DU
#define BANK0_INTFA 0x0EU
#define BANK0_INTFB 0x0FU
#define BANK0_INTCAPA 0x10U
#define BANK0_INTCAPB 0x11U
#define BANK0_GPIOA 0x12U
#define BANK0_GPIOB 0x13U
#define BANK0_OLATA 0x14U
#define BANK0_OLATB 0x15U

#define BANK1_IODIRA 0x00U
#define BANK1_IPOLA 0x01U
#define BANK1_GPINTENA 0x02U
#define BANK1_DEFVALA 0x03U
#define BANK1_INTCONA 0x04U
#define BANK1_IOCONA 0x05U
#define BANK1_GPPUA 0x06U
#define BANK1_INTFA 0x07U
#define BANK1_INTCAPA 0x08U
#define BANK1_GPIOA 0x09U
#define BANK1_OLATA 0x0AU
#define BANK1_IODIRB 0x10U
#define BANK1_IPOLB 0x11U
#define BANK1_GPINTENB 0x12U
#define BANK1_DEFVALB 0x13U
#define BANK1_INTCONB 0x14U
#define BANK1_IOCONB 0x15U
#define BANK1_GPPUB 0x16U
#define BANK1_INTFB 0x17U
#define BANK1_INTCAPB 0x18U
#define BANK1_GPIOB 0x19U
#define BANK1_OLATB 0x1AU

typedef struct
{
    uint8_t IO0 : 1;
    uint8_t IO1 : 1;
    uint8_t IO2 : 1;
    uint8_t IO3 : 1;
    uint8_t IO4 : 1;
    uint8_t IO5 : 1;
    uint8_t IO6 : 1;
    uint8_t IO7 : 1;
} IODIR_t;
typedef struct
{
    uint8_t IP0 : 1;
    uint8_t IP1 : 1;
    uint8_t IP2 : 1;
    uint8_t IP3 : 1;
    uint8_t IP4 : 1;
    uint8_t IP5 : 1;
    uint8_t IP6 : 1;
    uint8_t IP7 : 1;
} IPOL_t;
typedef struct
{
    uint8_t INT0 : 1;
    uint8_t INT1 : 1;
    uint8_t INT2 : 1;
    uint8_t INT3 : 1;
    uint8_t INT4 : 1;
    uint8_t INT5 : 1;
    uint8_t INT6 : 1;
    uint8_t INT7 : 1;
} GPINTEN_t;
typedef struct
{
    uint8_t DEF0 : 1;
    uint8_t DEF1 : 1;
    uint8_t DEF2 : 1;
    uint8_t DEF3 : 1;
    uint8_t DEF4 : 1;
    uint8_t DEF5 : 1;
    uint8_t DEF6 : 1;
    uint8_t DEF7 : 1;
} DEFVAL_t;
typedef struct
{
    uint8_t IOC0 : 1;
    uint8_t IOC1 : 1;
    uint8_t IOC2 : 1;
    uint8_t IOC3 : 1;
    uint8_t IOC4 : 1;
    uint8_t IOC5 : 1;
    uint8_t IOC6 : 1;
    uint8_t IOC7 : 1;
} INTCON_t;
typedef struct
{
    uint8_t RESERVED : 1;
    uint8_t INTPOL : 1;
    uint8_t ODR : 1;
    uint8_t HAEN : 1;
    uint8_t DISSLW : 1;
    uint8_t SEQOP : 1;
    uint8_t MIRROR : 1;
    uint8_t BANK : 1;
} IOCON_t;
typedef struct
{
    uint8_t PU0 : 1;
    uint8_t PU1 : 1;
    uint8_t PU2 : 1;
    uint8_t PU3 : 1;
    uint8_t PU4 : 1;
    uint8_t PU5 : 1;
    uint8_t PU6 : 1;
    uint8_t PU7 : 1;
} GPPU_t;
typedef struct
{
    uint8_t INT0 : 1;
    uint8_t INT1 : 1;
    uint8_t INT2 : 1;
    uint8_t INT3 : 1;
    uint8_t INT4 : 1;
    uint8_t INT5 : 1;
    uint8_t INT6 : 1;
    uint8_t INT7 : 1;
} INTF_t;
typedef struct
{
    uint8_t ICP0 : 1;
    uint8_t ICP1 : 1;
    uint8_t ICP2 : 1;
    uint8_t ICP3 : 1;
    uint8_t ICP4 : 1;
    uint8_t ICP5 : 1;
    uint8_t ICP6 : 1;
    uint8_t ICP7 : 1;
} INTCAP_t;
typedef struct
{
    uint8_t GP0 : 1;
    uint8_t GP1 : 1;
    uint8_t GP2 : 1;
    uint8_t GP3 : 1;
    uint8_t GP4 : 1;
    uint8_t GP5 : 1;
    uint8_t GP6 : 1;
    uint8_t GP7 : 1;
} GPIO_t;
typedef struct
{
    uint8_t OL0 : 1;
    uint8_t OL1 : 1;
    uint8_t OL2 : 1;
    uint8_t OL3 : 1;
    uint8_t OL4 : 1;
    uint8_t OL5 : 1;
    uint8_t OL6 : 1;
    uint8_t OL7 : 1;
} OLAT_t;
typedef struct
{
    struct
    {
        union {
            uint8_t byte;
            IODIR_t bits;
        } iodira;
        union {
            uint8_t byte;
            IODIR_t bits;
        } iodirb;
        //        union{
        //             uint8_t byte;
        //            IPOL_t bits;
        //        }ipola;
        //        union{
        //             uint8_t byte;
        //            IPOL_t bits;
        //        }ipolb;
        //        union{
        //             uint8_t byte;
        //            GPINTEN_t bits;
        //        }gpintena;
        //        union{
        //             uint8_t byte;
        //            GPINTEN_t bits;
        //        }gpintenb;
        union {
            uint8_t byte;
            DEFVAL_t bits;
        } defvala;
        union {
            uint8_t byte;
            DEFVAL_t bits;
        } defvalb;
        //        union{
        //             uint8_t byte;
        //            INTCON_t bits;
        //        }intcona;
        //        union{
        //             uint8_t byte;
        //            INTCON_t bits;
        //        }intconb;
        union {
            uint8_t byte;
            IOCON_t bits;
        } iocona;
        union {
            uint8_t byte;
            IOCON_t bits;
        } ioconb;
        //        union{
        //             uint8_t byte;
        //            GPPU_t bits;
        //        }gppua;
        //        union{
        //             uint8_t byte;
        //            GPPU_t bits;
        //        }gppub;
        //        union{
        //             uint8_t byte;
        //            INTF_t bits;
        //        }intfa;
        //        union{
        //             uint8_t byte;
        //            INTF_t bits;
        //        }intfb;
        //        union{
        //             uint8_t byte;
        //            INTCAP_t bits;
        //        }intcapa;
        //        union{
        //             uint8_t byte;
        //            INTCAP_t bits;
        //        }intcapb;
        //        union{
        //             uint8_t byte;
        //            GPIO_t bits;
        //        }gpioa;
        //        union{
        //             uint8_t byte;
        //            GPIO_t bits;
        //        }gpiob;
        //        union{
        //             uint8_t byte;
        //            OLAT_t bits;
        //        }olata;
        //        union{
        //             uint8_t byte;
        //            OLAT_t bits;
        //        }olatb;
    };
    uint8_t devaddr;
} mcp23s17_t;

int32_t mcp23s17_init(mcp23s17_t *p, uint8_t id, uint16_t dir, uint16_t def);
int32_t mcp23s17_write(mcp23s17_t *p, uint8_t regaddr, uint8_t regvalue);
int32_t mcp23s17_read(mcp23s17_t *p, uint8_t regaddr, uint8_t *pregvalue);
int32_t mcp23s17_write16(mcp23s17_t *p, uint8_t regaddr, uint16_t regvalue);
int32_t mcp23s17_read16(mcp23s17_t *p, uint8_t regaddr, uint16_t *pregvalue);

#endif
